package gatperdut.chato.core.messaging;

import gatperdut.chato.core.ChatoServer;
import gatperdut.chato.core.messaging.grammar.BailMessagingGrammarLexer;
import gatperdut.chato.core.messaging.grammar.generated.MessagingGrammarParser;
import gatperdut.chato.core.messaging.grammar.generated.MessagingGrammarParser.CommandContext;
import gatperdut.chato.core.messaging.grammar.messinfo.CreateItemTemplateInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.CreatePlayerInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.CreateRoomInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.ListItemTemplatesInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.ListItemsInRoomInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.ListPlayersInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.ListRoomsInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.MessageInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.UpdateItemsInfo;
import gatperdut.chato.core.messaging.grammar.messinfo.UpdateRoomsInfo;
import gatperdut.chato.core.messaging.replies.CreateItemTemplateReply;
import gatperdut.chato.core.messaging.replies.CreatePlayerReply;
import gatperdut.chato.core.messaging.replies.CreateRoomReply;
import gatperdut.chato.core.messaging.replies.ListItemTemplatesReply;
import gatperdut.chato.core.messaging.replies.ListItemsInRoomReply;
import gatperdut.chato.core.messaging.replies.ListPlayersReply;
import gatperdut.chato.core.messaging.replies.ListRoomsReply;
import gatperdut.chato.core.messaging.replies.Reply;
import gatperdut.chato.core.messaging.replies.UpdateItemsReply;
import gatperdut.chato.core.messaging.replies.UpdateRoomsReply;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStream;

public class MessageInterpreter {

    private final ChatoServer chatoServer;

    public MessageInterpreter( ChatoServer chatoServer ) {
        this.chatoServer = chatoServer;
    }

    public String exec( String message ) {
        CharStream charStream = new ANTLRInputStream( message );
        BailMessagingGrammarLexer lexer = new BailMessagingGrammarLexer( charStream );

        TokenStream tokenStream = new CommonTokenStream( lexer );
        MessagingGrammarParser parser = new MessagingGrammarParser( tokenStream );
        parser.setErrorHandler( new BailErrorStrategy() );

        CommandContext cc = null;
        try {
            cc = parser.command();
        }
        catch ( Exception mte ) {
            // Badly formed message
            mte.printStackTrace();
            return null;
        }

        MessageInfo mi = cc.messageInfo;
        if ( mi == null ) {
            // We don't know how to process the message.
            return null;
        }
        Reply reply = createReply( mi );

        return reply.send();
    }

    private Reply createReply( MessageInfo mi ) {
        Reply r = null;

        // TODO: action class and info class as fields of the enum literals.
        switch ( mi.getMessageType() ) {
        case LIST_ROOMS:
            r = new ListRoomsReply( (ListRoomsInfo) mi, getChatoServer() );
            break;
        case LIST_PLAYERS:
            r = new ListPlayersReply( (ListPlayersInfo) mi, getChatoServer() );
            break;
        case LIST_ITEM_TEMPLATES:
            r = new ListItemTemplatesReply( (ListItemTemplatesInfo) mi, getChatoServer() );
            break;
        case LIST_ITEMS_IN_ROOM:
            r = new ListItemsInRoomReply( (ListItemsInRoomInfo) mi, getChatoServer() );
            break;
        case CREATE_ROOM:
            r = new CreateRoomReply( (CreateRoomInfo) mi, getChatoServer() );
            break;
        case CREATE_PLAYER:
            r = new CreatePlayerReply( (CreatePlayerInfo) mi, getChatoServer() );
            break;
        case CREATE_ITEM_TEMPLATE:
            r = new CreateItemTemplateReply( (CreateItemTemplateInfo) mi, getChatoServer() );
            break;
        case UPDATE_ROOMS:
            r = new UpdateRoomsReply( (UpdateRoomsInfo) mi, getChatoServer() );
            break;
        case UPDATE_ITEMS:
            r = new UpdateItemsReply( (UpdateItemsInfo) mi, getChatoServer() );
            break;
        default:
            throw new IllegalArgumentException( "Creating reply with unsupported info." );
        }

        return r;
    }

    public ChatoServer getChatoServer() {
        return chatoServer;
    }

}
